package top.zhangjianyong.blog.service.impl;

import static top.zhangjianyong.blog.enums.RespCode.*;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.zhangjianyong.blog.entity.dto.MenuDTO;
import top.zhangjianyong.blog.entity.po.Menu;
import top.zhangjianyong.blog.entity.po.RoleMenu;
import top.zhangjianyong.blog.entity.po.User;
import top.zhangjianyong.blog.entity.po.UserRole;
import top.zhangjianyong.blog.mapper.MenuMapper;
import top.zhangjianyong.blog.params.menu.MenuRemoveParam;
import top.zhangjianyong.blog.params.menu.MenuSaveOrUpdateParam;
import top.zhangjianyong.blog.response.ApiResponse;
import top.zhangjianyong.blog.service.MenuService;
import top.zhangjianyong.blog.service.RoleMenuService;

/**
 * 菜单Service
 *
 * @author HDN
 * @since 2024/7/21 上午8:47
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

  private final RoleMenuService roleMenuService;

  public MenuServiceImpl(RoleMenuService roleMenuService) {
    this.roleMenuService = roleMenuService;
  }

  @Override
  public ApiResponse treeList() {
    MPJLambdaWrapper<Menu> wrapper =
        new MPJLambdaWrapper<Menu>()
            .eq(Menu::getPid, 0)
            .orderByAsc(Menu::getSort)
            .selectAll(Menu.class)
            .selectCollection(Menu.class, MenuDTO::getChildren)
            .leftJoin(Menu.class, Menu::getPid, Menu::getId, ext -> ext.orderByAsc(Menu::getSort));
    List<MenuDTO> menuDTOS = baseMapper.selectJoinList(MenuDTO.class, wrapper);
    return ApiResponse.success(menuDTOS);
  }

  @Override
  public ApiResponse saveOrUpdate(MenuSaveOrUpdateParam param) {
    Menu menu = new Menu();
    BeanUtils.copyProperties(param, menu);

    boolean result = menu.getId() == null ? save(menu) : updateById(menu);
    return result ? ApiResponse.success() : ApiResponse.fail(MENU_SAVE_OR_UPDATE_ROLE_ERROR);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public ApiResponse remove(MenuRemoveParam param) {
    boolean remove = removeById(param.id());
    if (!remove) return ApiResponse.fail(MENU_REMOVE_ERROR);
    boolean removeRole = roleMenuService.removeByMenu(param.id());
    if (!removeRole) return ApiResponse.fail(MENU_CLEAR_ERROR);
    clearChildren(param.id());
    return ApiResponse.success();
  }

  // 清理子菜单
  private void clearChildren(Long id) {
    List<Menu> list = lambdaQuery().select(Menu::getId).eq(Menu::getPid, id).list();
    list.stream().map(Menu::getId).forEach(this::clearChildren);
    lambdaUpdate().eq(Menu::getPid, id).remove();
  }

  @Override
  public List<MenuDTO> menu(Long userId) {

    MPJLambdaWrapper<Menu> wrapper =
        new MPJLambdaWrapper<Menu>()
            .selectAll(Menu.class)
            .orderByAsc(Menu::getSort)
            .innerJoin(RoleMenu.class, RoleMenu::getMenuId, Menu::getId)
            .innerJoin(UserRole.class, UserRole::getRoleId, RoleMenu::getRoleId)
            .innerJoin(User.class, User::getId, UserRole::getUserId)
            .selectCollection(Menu.class, MenuDTO::getChildren)
            .leftJoin(Menu.class, Menu::getPid, Menu::getId, ext -> ext.orderByAsc(Menu::getSort))
            .eq(User::getId, userId)
            .eq(Menu::getPid, 0);
    return baseMapper.selectJoinList(MenuDTO.class, wrapper);
  }
}
